/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package si.ibloc.cms.logic.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.datamodel.DataModelSelection;
import org.jboss.seam.annotations.web.RequestParameter;
import si.ibloc.cms.logic.interfaces.FullTextSearch;
import si.ibloc.cms.model.Article;
import si.ibloc.cms.model.Content;
import si.ibloc.cms.model.File;

/**
 * @author <a href="mailto:ales.justin@jboss.com">Ales Justin</a>
 */
@Stateful
@Name("search")
public class FullTextSearchImpl implements FullTextSearch, Serializable {
   private static final long serialVersionUID = 3308358180071134843L;

   transient @PersistenceContext EntityManager em;
   @RequestParameter Long id;

   int pageSize = 2;
   int currentPage = 0;
   boolean hasMore = false;
   int numberOfResults;

   String searchQuery;

   @DataModel List<Content> searchResults;
   @DataModelSelection Content selectedContent;

   @Out(required = false) Content content;

   @Out(scope = ScopeType.CONVERSATION, required = false)
   Map<Content, Boolean> searchSelections;

   protected void updateResults() {
       FullTextQuery query;
       try {
           query = searchQuery(searchQuery);
       } catch (ParseException pe) {
           return;
       }

       List<Content> items = query
           .setMaxResults(pageSize + 1)
           .setFirstResult(pageSize * currentPage)
           .getResultList();
       numberOfResults = query.getResultSize();

       if (items.size() > pageSize) {
           searchResults = new ArrayList<Content>(items.subList(0, pageSize));
           hasMore = true;
       } else {
           searchResults = items;
           hasMore = false;
       }

       searchSelections = new HashMap<Content, Boolean>();
   }

   protected FullTextQuery searchQuery(String searchQuery) throws ParseException {
       Map<String,Float> boostPerField = new HashMap<String,Float>();
       boostPerField.put("title", 4f);
       boostPerField.put("content", 2f);
       boostPerField.put("author.name", 1f);

       String[] productFields = {"title", "content", "author.name"};
       QueryParser parser = new MultiFieldQueryParser(productFields, new StandardAnalyzer(), boostPerField);
       parser.setAllowLeadingWildcard(true);
       org.apache.lucene.search.Query luceneQuery = parser.parse(searchQuery);
       return ((FullTextEntityManager)em).createFullTextQuery(luceneQuery, Article.class, File.class);
   }

   // --------------

   public String getSearchQuery() {
      return searchQuery;
   }

   public void setSearchQuery(String searchQuery) {
      this.searchQuery = searchQuery;
   }

   public int getNumberOfResults() {
      return numberOfResults;
   }

   public void nextPage() {
      if (!isLastPage()) {
         currentPage++;
         updateResults();
      }
   }

   public void prevPage() {
      if (!isFirstPage()) {
         currentPage--;
         updateResults();
      }
   }

   public boolean isLastPage() {
      return (searchResults != null) && !hasMore;
   }

   public boolean isFirstPage() {
      return (searchResults != null) && (currentPage == 0);
   }

   @Begin(join = true)
   public String doSearch() {
      currentPage = 0;
      updateResults();

      return "browse";
   }

   @Begin(join = true)
   public void selectFromRequest() {
       if (id != null)  {
           content = em.find(Content.class, id);
       } else if (selectedContent != null) {
           content = selectedContent;
       }
   }

   public int getPageSize() {
       return pageSize;
   }

   public void setPageSize(int pageSize) {
       this.pageSize = pageSize;
   }

   @End public void reset() { }

   @Remove @Destroy public void destroy() { }
}
